home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Networking / GetEnetAddrDirect.ppc / GetEnetAddrDirect.c next >
Encoding:
C/C++ Source or Header  |  1998-09-02  |  10.9 KB  |  429 lines  |  [TEXT/CWIE]

  1. /*
  2.     File: GetEnetAddrDirect.c
  3.  
  4. This is a sample program to obtain the ethernet address from a Power Mac using
  5. 1. direct access to the ROM for the 61/71/8100 Power Macs, or by accessing the
  6. Name Registry for PCI based systems. This means that the the address can be 
  7. accessed without Open Transport being available, or without having to open the
  8. Ethernet device driver.
  9.  
  10. 2. use OpenTransport to display the ethernet address for all ethernet devices
  11. that are detected.  For this method to work, the program opens a connection over
  12. the found ethernet port. If the openConnection call works, then we can use the 
  13. OT APIs to obtain the ethernet address.
  14.  
  15. For the earlier Power Macs, 6100/ 7100/8100, the Burned In Address is found in 
  16. ROM at address 0x50f08000.  One must read every 16 bytes for each of the 6
  17. bytes that make up the address. That is you'll need to 
  18. read address 50f08000, 50f08010, 50f08020, 50f08030, 50f08040, 
  19. and  50f08050.  The found address is byte swapped. which means
  20.  
  21. 10 00 E0 2B 06 AF, which if you bit invert each byte becomes
  22.  
  23. 08 00 07 D4 60 F5.
  24.  
  25. For PCI Power Macs, the burned in address is generally in 
  26. the Name Registry, however, the name of the entry is vendor 
  27. specified.  For the 72/73/75/76/85/86/95/9600 Power Macs, look at the
  28. "local-mac-address" entry. For the PCI Power Macs which use the Comm Slot2
  29. card, look at the "ASNT,ethernet-address" entry for a pointer to where the
  30. ethernet address is stored.
  31.  
  32. The one set of Power Macs, that this program does not demonstrate how to access
  33. using the direct means are the 52/53/62/6300 systems which use the original
  34. CommSlot Ethernet card and which can also use the PDS slot LC style ethernet
  35. card
  36.  
  37. */
  38.  
  39. #include <MacTypes.h>
  40. #include <Gestalt.h>
  41. #include <Errors.h>
  42. #include <NameRegistry.h>
  43. #include <stdio.h>
  44. #include <Strings.h>
  45. #include <OpenTransport.h>
  46. #include <OpenTptLinks.h>
  47. #include <OpenTptConfig.h>
  48.  
  49.  
  50. enum {
  51.     kUnsupported         = 0,
  52.     kPDMMachine            = 1,
  53.     kPCIMachine            = 2,
  54.     kCommSlotMachine    = 3,
  55.     kPCIComm2Machine     = 4
  56. };
  57.  
  58. enum {
  59.     kPDMEnetROMBase    = 0x50f08000
  60. };
  61.  
  62. enum {
  63.     gestaltPowerBookG3Series         = 312,
  64.     gestaltPowerBookG3SeriesFSTN     = 314,
  65.     gestaltiMac                        = 406,
  66.     gestaltPowerMacG3                 = 510
  67. };
  68.  
  69. struct Address8022
  70. {
  71.     OTAddressType    fAddrFamily;
  72.     UInt8            fHWAddr[k48BitAddrLength];
  73.     UInt16            fSAP;
  74.     UInt8            fSNAP[k8022SNAPLength];
  75. };
  76. typedef struct Address8022 Address8022;
  77.  
  78. UInt32         DoesCPUHaveBuiltInEthernet(void);
  79. UInt8        ByteSwapValue(UInt8 val);
  80. OSStatus     GetPDMBuiltInEnetAddr(UInt8 *enetaddr);
  81. OSStatus     GetPCIBuiltInEnetAddr(UInt8 *enetaddr);
  82. OSStatus     GetPCIComm2EnetAddr(UInt8 *enetaddr);
  83. void        DisplayEnetAddr(UInt8 *enetaddr);
  84. void        DisplayBurnedInAddress(void);
  85. void         DisplayOTEthernetAddresses(void);
  86.  
  87.  
  88. UInt32 DoesCPUHaveBuiltInEthernet(void)
  89. {
  90.     long        response;
  91.     OSStatus    err;
  92.     UInt32        result = kUnsupported;
  93.     
  94.     err = Gestalt(gestaltMachineType, &response);
  95.     switch (response)
  96.     {
  97.         case gestaltPowerMac8100_120:
  98.         case gestaltAWS9150_80:
  99.         case gestaltPowerMac8100_110:
  100.         case gestaltPowerMac7100_80:
  101.         case gestaltPowerMac8100_100:
  102.         case gestaltAWS9150_120:
  103.         case gestaltPowerMac8100_80:
  104.         case gestaltPowerMac6100_60:
  105.         case gestaltPowerMac6100_66:
  106.         case gestaltPowerMac7100_66:
  107.             result = kPDMMachine;
  108.             break;
  109.         
  110.         case gestaltPowerMac9500:
  111.         case gestaltPowerMac7500:
  112.         case gestaltPowerMac8500:
  113.         case gestaltPowerBook3400:
  114.         case gestaltPowerBookG3:
  115.         case gestaltPowerMac7200:
  116.         case gestaltPowerMac7300:
  117.         case gestaltPowerBookG3Series:
  118.         case gestaltPowerBookG3SeriesFSTN:
  119.         case gestaltPowerMacG3:
  120.         case gestaltiMac:
  121.         case gestaltPowerBook3400:
  122.             result = kPCIMachine;
  123.             break;
  124.             
  125.         case gestaltPowerMac5200:
  126.         case gestaltPowerMac6200:
  127.             result = kCommSlotMachine;
  128.             break;
  129.             
  130.         case gestaltPowerMac6400:
  131.         case gestaltPowerMac5400:
  132.         case gestaltPowerMac5500:
  133.         case gestaltPowerMac6500:
  134.         case gestaltPowerMac4400_160:
  135.         case gestaltPowerMac4400:
  136.             result = kPCIComm2Machine;
  137.         
  138.     }
  139.     
  140.     if (response == kUnsupported)
  141.     {
  142.         err = Gestalt(gestaltNameRegistryVersion, (long*) &response);
  143.         if (err == noErr)
  144.             result = kPCIMachine;
  145.     }
  146.     return result;
  147. }
  148.  
  149. UInt8        ByteSwapValue(UInt8 val)
  150. {
  151.     UInt8    result = 0;
  152.     
  153.     if (val & 0x01)
  154.         result |= 0x80;
  155.         
  156.     if (val & 0x02)
  157.         result |= 0x40;
  158.         
  159.     if (val & 0x04)
  160.         result |= 0x20;
  161.         
  162.     if (val & 0x08)
  163.         result |= 0x10;
  164.         
  165.     if (val & 0x10)
  166.         result |= 0x08;
  167.         
  168.     if (val & 0x20)
  169.         result |= 0x04;
  170.         
  171.     if (val & 0x40)
  172.         result |= 0x02;
  173.         
  174.     if (val & 0x80)
  175.         result |= 0x01;
  176.     return result;
  177. }
  178.  
  179. OSStatus     GetPDMBuiltInEnetAddr(UInt8 *enetaddr)
  180. {
  181.     UInt32    i;
  182.     UInt8    *val;
  183.  
  184.     for (i = 0; i < 6; i++)
  185.     {
  186.         val = (UInt8 *)(kPDMEnetROMBase + i * 0x10);
  187.         enetaddr[i] = ByteSwapValue(*val);
  188.     }
  189.     return noErr;
  190. }
  191.  
  192.  
  193. OSStatus     GetPCIBuiltInEnetAddr(UInt8 *enetaddr)
  194. {
  195.     OSStatus                err = noErr;
  196.     RegEntryIter            cookie;
  197.     RegEntryID              theFoundEntry;
  198.     unsigned char              enetAddrStr[32] = "\plocal-mac-address";
  199.     RegCStrEntryNamePtr     enetAddrCStr = p2cstr( enetAddrStr );
  200.     RegEntryIterationOp     iterOp;
  201.     UInt8                    enetAddr[6];
  202.     Boolean                 done = false;
  203.     RegPropertyValueSize    theSize;
  204.     
  205.     err = RegistryEntryIDInit( &theFoundEntry );
  206.     if (err != noErr)
  207.     {
  208.         fprintf(stdout, "RegistryEntryIDInit failed\n");
  209.         return err;
  210.     }
  211.  
  212.     err = RegistryEntryIterateCreate( &cookie );
  213.     if (err != noErr)
  214.     {
  215.         fprintf(stdout, "RegistryEntryIterateCreate failed\n");
  216.         return err;
  217.     }
  218.  
  219.     iterOp = kRegIterDescendants;
  220.  
  221.     err = RegistryEntrySearch( &cookie, iterOp, &theFoundEntry, &done,
  222.                                                        enetAddrCStr, nil, 0);
  223.     
  224.     if (err == noErr)
  225.     {
  226.         theSize = sizeof(enetAddr);;
  227.         err = RegistryPropertyGet(&theFoundEntry, enetAddrCStr, &enetAddr, &theSize );
  228.         if (err == noErr)
  229.             BlockMove(enetAddr, enetaddr, sizeof(enetAddr));
  230.     }
  231.  
  232.     RegistryEntryIterateDispose( &cookie );
  233.  
  234.     return noErr;
  235. }
  236.  
  237. OSStatus     GetPCIComm2EnetAddr(UInt8 *enetaddr)
  238. {
  239.     OSStatus                err = noErr;
  240.     RegEntryIter            cookie;
  241.     RegEntryID              theFoundEntry;
  242.     unsigned char              enetAddrStr[32] = "\pASNT,ethernet-address";
  243.     RegCStrEntryNamePtr     enetAddrCStr = p2cstr( enetAddrStr );
  244.     RegEntryIterationOp     iterOp;
  245.     UInt8                    *enetAddr;
  246.     Boolean                 done = false;
  247.     RegPropertyValueSize    theSize;
  248.     
  249.     err = RegistryEntryIDInit( &theFoundEntry );
  250.     if (err != noErr)
  251.     {
  252.         fprintf(stdout, "RegistryEntryIDInit failed\n");
  253.         return err;
  254.     }
  255.  
  256.     err = RegistryEntryIterateCreate( &cookie );
  257.     if (err != noErr)
  258.     {
  259.         fprintf(stdout, "RegistryEntryIterateCreate failed\n");
  260.         return err;
  261.     }
  262.  
  263.     iterOp = kRegIterDescendants;
  264.  
  265.     err = RegistryEntrySearch( &cookie, iterOp, &theFoundEntry, &done,
  266.                                                        enetAddrCStr, nil, 0);
  267.     
  268.     if (err == noErr)
  269.     {
  270.         theSize = sizeof(enetAddr);;
  271.         err = RegistryPropertyGet(&theFoundEntry, enetAddrCStr, &enetAddr, &theSize );
  272.         if (err == noErr)
  273.             BlockMove(enetAddr, enetaddr, 6);
  274.     }
  275.  
  276.     RegistryEntryIterateDispose( &cookie );
  277.  
  278.     return noErr;
  279. }
  280.  
  281. void        DisplayEnetAddr(UInt8 *enetaddr)
  282. {    
  283.     fprintf(stdout, "%02X.",(int )enetaddr[0]);
  284.     fprintf(stdout, "%02X.",(int )enetaddr[1]);
  285.     fprintf(stdout, "%02X.",(int )enetaddr[2]);
  286.     fprintf(stdout, "%02X.",(int )enetaddr[3]);
  287.     fprintf(stdout, "%02X.",(int )enetaddr[4]);
  288.     fprintf(stdout, "%02X",(int )enetaddr[5]);
  289. }
  290.  
  291. void DisplayBurnedInAddress(void)
  292. {
  293.     OSStatus    err;
  294.     UInt32        cputype;
  295.     UInt8        enetaddr[6];
  296.  
  297.     fprintf(stdout, "First, get the burned-in ethernet address directly from ROM or NameRegistry\n");
  298.     cputype = DoesCPUHaveBuiltInEthernet();
  299.     switch (cputype)
  300.     {
  301.         case kPDMMachine:
  302.             err = GetPDMBuiltInEnetAddr((UInt8*)enetaddr);
  303.             if (err == noErr)
  304.             {
  305.                 fprintf(stdout, "\nBurned-In address for Ethernet Built-In => ");
  306.                 DisplayEnetAddr((UInt8*)&enetaddr);
  307.             }
  308.             break;
  309.         
  310.         case kPCIMachine:
  311.             err = GetPCIBuiltInEnetAddr((UInt8*)enetaddr);
  312.             if (err == noErr)
  313.             {
  314.                 fprintf(stdout, "\nBurned-In address for Ethernet Built-In => ");
  315.                 DisplayEnetAddr((UInt8*)&enetaddr);
  316.             }
  317.             break;
  318.         
  319.         case kCommSlotMachine:
  320.             fprintf(stdout, "\n\nThis is a NuBus based Power Mac which may have a CommSlot Ethernet card");
  321.             fprintf(stdout, "\nmust use Open Transport to obtain the ethernet address");
  322.             break;
  323.         
  324.         case kPCIComm2Machine:
  325.             fprintf(stdout, "\n\nThis is a PCI system which may have a CommSlot2 Ethernet card");
  326.             fprintf(stdout, "\nmust use Open Transport to obtain the ethernet address");
  327.             break;
  328.         
  329.         default:
  330.             fprintf(stdout, "\n It appears that this CPU does not have built-in ethernet\n");
  331.             break;
  332.     }
  333. }
  334.  
  335. void DisplayOTEthernetAddresses(void)
  336. {
  337.     OSStatus         status;
  338.     EndpointRef        ep;
  339.     OTPortRecord    devicePortRecord;
  340.     UInt32            index;
  341.     TBind            returnInfo;
  342.     TBind            requestInfo;
  343.     Address8022     theReturnAddr =     {AF_8022, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x0000,
  344.                                         {0x00,0x00,0x00,0x00,0x00}};
  345.     Address8022     theAddr =     {AF_8022, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x8888,
  346.                                     {0x00,0x00,0x00,0x00,0x00}};
  347.     Boolean            foundAPort;
  348.     Str255            userFriendlyName;
  349.     
  350.     
  351.     if (status = InitOpenTransport())
  352.     {
  353.         fprintf(stdout, "\n\nOpen Transport is not installed or is inactive\n");
  354.         return;
  355.     }
  356.     else
  357.     {
  358.         fprintf(stdout, "\n\nNow checking for Ethernet addresses using Open Transport\n");
  359.         fprintf(stdout, "There will be a slight delay as I try to open a connection\n");
  360.         fprintf(stdout, "over each card.\n");
  361.     }
  362.  
  363.     index = 0;
  364.         // iterate thru each OT port record for ethernet ports.    
  365.     while (foundAPort = OTGetIndexedPort(&devicePortRecord,index))
  366.     {
  367.         if ((devicePortRecord.fCapabilities & kOTPortIsDLPI) &&
  368.             (devicePortRecord.fCapabilities & kOTPortIsTPI) &&
  369.             (kOTEthernetDevice == OTGetDeviceTypeFromPortRef(devicePortRecord.fRef)))
  370.         {
  371.     
  372.             ep = OTOpenEndpoint(OTCreateConfiguration(devicePortRecord.fPortName), (OTOpenFlags)NULL, NULL,&status);
  373.     
  374.             if (status == kOTNoError)
  375.             {
  376.                     // we have to bind the endpoint before we can get it's address info
  377.                 requestInfo.addr.buf = (UInt8 *)&theAddr;
  378.                 requestInfo.addr.len = 10;    // family type + Ethernet + type field
  379.                                 // don't use sizeof(theAddr) since we are binding to type 1 Ethernet
  380.                                 // address, not to an 802.2 address.
  381.                 requestInfo.addr.maxlen = 0;            
  382.                 requestInfo.qlen = 0;
  383.     
  384.                 status = OTBind(ep, &requestInfo, NULL);
  385.  
  386.                 if (status == kOTNoError)
  387.                 {
  388.                     returnInfo.addr.buf = (UInt8 *)&theReturnAddr;
  389.                     returnInfo.addr.maxlen = 10;            // family type + 6 bytes for Ethernet + type
  390.                     returnInfo.qlen = 0;
  391.                     
  392.                     
  393.                     status = OTGetProtAddress(ep,&returnInfo,NULL);
  394.                     
  395.                     if (status == kOTNoError)
  396.                     {
  397.                         OTGetUserPortNameFromPortRef(devicePortRecord.fRef, userFriendlyName);
  398.                         fprintf(stdout, "\n   The Ethernet address for %#s is => ", userFriendlyName);
  399.                         DisplayEnetAddr((UInt8*)&theReturnAddr.fHWAddr);
  400.                     }
  401.                     OTUnbind(ep);
  402.                 }
  403.                 
  404.                 OTCloseProvider(ep);
  405.             }    
  406.                 
  407.                 
  408.         }
  409.         index++;
  410.     }    
  411.     
  412.     
  413.     
  414.         // closing down
  415.     CloseOpenTransport();
  416.     
  417.     
  418. }
  419.  
  420. main (void)
  421. {
  422.     
  423.     fprintf(stdout, "Sample program to obtain the available ethernet addresses");
  424.     DisplayBurnedInAddress();
  425.     
  426.     DisplayOTEthernetAddresses();
  427.     return 0;
  428. }
  429.